#ifndef _PRE_PREPARE_HPP
#define _PRE_PREPARE_HPP 1

#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>

#include "RequestBatch.hpp"

#include "../constants.hpp"
#include "../Parameters.hpp"

#include "MacArrayMessage.hpp"
#include "NonDeterminism.hpp"
#include "HistoryDigest.hpp"
#include "SignedRequestCore.hpp"
#include "Digest.hpp"
#include "VerifiedMessageBase.hpp"

namespace BFT
{
	namespace order
	{
		namespace messages
		{
			class PrePrepare : public BFT::messages::MacArrayMessage
			{
				public:
				
				PrePrepare(uint32_t _view, uint32_t _seq, boost::shared_ptr<BFT::messages::HistoryDigest> _hist,
					   boost::shared_ptr<RequestBatch> _batch, boost::shared_ptr<BFT::messages::NonDeterminism> _non,
					   boost::shared_ptr<BFT::messages::Digest> _cp, uint32_t _sendingReplica);
					   
				PrePrepare(boost::shared_ptr<char> _bytes, int _bytes_size);
				
//				PrePrepare(const PrePrepare& other); //non default copy constructor to avoid compilation error
				
				bool equals(boost::shared_ptr<PrePrepare> _other_pp);
				
				uint32_t getView(); //inlined
				uint32_t getSeqNo(); //inlined
				uint32_t getSendingReplica(); //inlined
				
				boost::shared_ptr<BFT::messages::HistoryDigest> getHistory();//inlined
				boost::shared_ptr<RequestBatch> getRequestBatch(); //inlined
				boost::shared_ptr<BFT::messages::NonDeterminism> getNonDeterminism(); //inlined 
				boost::shared_ptr<BFT::messages::Digest> getCPHash(); //inlined
				
				void printInfo();
				
				void rcCleaned(); //synch
				void rcMasterCleaned(); //sync
				
				protected:
				
				uint32_t viewNo;
				uint32_t seqNo;
				boost::shared_ptr<BFT::messages::HistoryDigest> history;
				boost::shared_ptr<RequestBatch> reqBatch;
				boost::shared_ptr<BFT::messages::NonDeterminism> nondet;
				boost::shared_ptr<BFT::messages::Digest> cpHash;
				
				unsigned int cleanCount;
				
				private:
				
				static uint32_t computeSize(uint32_t _view, uint32_t _seq, 
							    boost::shared_ptr<BFT::messages::HistoryDigest> _history,
							    boost::shared_ptr<RequestBatch> _reqBatch,
							    boost::shared_ptr<BFT::messages::NonDeterminism> _nondet,
							    boost::shared_ptr<BFT::messages::Digest> _cp);
							    
				boost::recursive_mutex cond_mutex;
				boost::condition_variable_any cleancount_condition;
			};
			
			
			inline uint32_t PrePrepare::getView() {return viewNo;}
			inline uint32_t PrePrepare::getSeqNo() {return seqNo;}
			inline uint32_t PrePrepare::getSendingReplica() {return getSender();}
			
			inline boost::shared_ptr<BFT::messages::HistoryDigest> PrePrepare::getHistory() {return history;}
			inline boost::shared_ptr<RequestBatch> PrePrepare::getRequestBatch() {return reqBatch;}
			inline boost::shared_ptr<BFT::messages::NonDeterminism> PrePrepare::getNonDeterminism() {return nondet;}
			inline boost::shared_ptr<BFT::messages::Digest> PrePrepare::getCPHash() {return cpHash;}
		}
	}
}

#endif
